#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>

#include "Globals.h"
#include "Common.h"
#include "Menu.h"

volatile int buttonPushed = 0;
volatile int triggerPulled = 0;
volatile int configMode = 0;


int main (void) {
	
	PCMSK1 |= (1 << PCINT10);  //Enable interrupts on PCINT10 (trigger)
	PCMSK1 |= (1 << PCINT9);  // Enable interrupts for the push button
	GIMSK = (1 << PCIE1);    //Enable interrupts period for PCI0 (PCINT11:8

	initialize();
		
	setOutputPin(12);
	setOutputPin(11);
	setInputPin(7);
	setInputPin(5);
	setOutputPin(6);
	setInputPin(3); // Push button
	
	////////////////////////////////////
	// Enable pull up on trigger inputs
	////////////////////////////////////
	
	// Trigger
	pinOutput(5, HIGH); // Trigger
	pinOutput(7, HIGH); // Trigger
	
	pinOutput(3, HIGH); // Push Button
	pinOutput(13, HIGH);
	pinOutput(10, HIGH);
	pinOutput(9, LOW);
	pinOutput(8, LOW);
	pinOutput(12, LOW);
	
	// turn on green LED
	pinOutput(11, LOW); // Green LED
	int state = LOW;
	
	// If the button is held during startup, enter config mode.
	int buttonHeldTime = 0;
	while (pinHasInput(3)) {
		delay_ms(1);
		buttonHeldTime++;
	}
	
	if (buttonHeldTime >= 1000) {
		configMode = 1;
		
		// Some firing modes have 0 PULL_DEBOUNCE
		// Reset so the menus work.
		PULL_DEBOUNCE = RELEASE_DEBOUNCE;
	}
	
	sei(); // Enable interrupts
	
	if (configMode) {
		handleConfig();
	} else {
		while(1) {			
			for (int i = 0; i <= CURRENT_PRESET; i++) {		
				pinOutput(11, HIGH);
				delay_ms(200);
				pinOutput(11, LOW);
				delay_ms(200);
			}
			
			delay_ms(800);
		}
	}	
	return 1;
}

ISR(PCINT1_vect) {	
	if (triggerPulled == 0 && pinHasInput(5)) {

		if (!configMode) {
			fireMethod();
			delay_ms(PULL_DEBOUNCE);
		} else {
			int buttonHeldTime = 0;
			delay_ms(PULL_DEBOUNCE);
			while (pinHasInput(5)) {
				delay_ms(1);
				buttonHeldTime += 1;
			}
			configTriggerPulled(buttonHeldTime);
			
			// Debounce is included in configTriggerPulled.
		}		

		triggerPulled = 1;
	}

	if (triggerPulled == 1 && !pinHasInput(5)) {
		if (!configMode && fireOnTriggerRelease) {
			fireOnTriggerRelease();
		}
					
		delay_ms(RELEASE_DEBOUNCE);
		triggerPulled = 0;
	}
	
	if (buttonPushed == 0 && pinHasInput(3)) {
		togglePreset();
		delay_ms(20);
		buttonPushed = 1;
	}
	
	if (buttonPushed == 1 && !pinHasInput(3)) {
		delay_ms(20);
		buttonPushed = 0;
	}				
}



void initialize() {
	EEPROM_BALLS_PER_SECOND[0] = EEPROM_BALLS_PER_SECOND_1;
	EEPROM_FIRING_MODE[0] = EEPROM_FIRING_MODE_1;
	EEPROM_BURST_SIZE[0] = EEPROM_BURST_SIZE_1;

	EEPROM_BALLS_PER_SECOND[1] = EEPROM_BALLS_PER_SECOND_2;
	EEPROM_FIRING_MODE[1] = EEPROM_FIRING_MODE_2;
	EEPROM_BURST_SIZE[1] = EEPROM_BURST_SIZE_2;

	EEPROM_BALLS_PER_SECOND[2] = EEPROM_BALLS_PER_SECOND_3;
	EEPROM_FIRING_MODE[2] = EEPROM_FIRING_MODE_3;
	EEPROM_BURST_SIZE[2] = EEPROM_BURST_SIZE_3;

	CURRENT_PRESET = eeprom_read_byte(&EEPROM_PRESET);
	if (CURRENT_PRESET < 0 || CURRENT_PRESET > (MAX_PRESETS - 1)) {
		CURRENT_PRESET = 0;
	}

	loadPreset();
}

void threeRoundBurst() {
	for (int i = 0; i < BURST_SIZE; i++) {
		pinOutput(6, HIGH);
		delay_ms(DWELL);
		pinOutput(6, LOW);
		
		// don't delay on the last round
		if (i < (BURST_SIZE - 1)) {
			delay_ms(ROUND_DELAY);
		}
	}
}

void fullAuto() {
	while (pinHasInput(7)) {
		singleShot();
		delay_ms(ROUND_DELAY);
	}
}

void singleShot() {
	pinOutput(6, HIGH);
	delay_ms(DWELL);
	pinOutput(6, LOW);
}

void togglePreset(){
	if (CURRENT_PRESET >= (MAX_PRESETS - 1)) {
		CURRENT_PRESET = 0;
	} else {
		CURRENT_PRESET++;
	}
	
	eeprom_write_byte(&EEPROM_PRESET, CURRENT_PRESET);
	
	loadPreset();
}